package com.mgq.netty.chat.protocol;

import com.google.gson.*;

import java.io.*;
import java.lang.reflect.Type;
import java.nio.charset.StandardCharsets;

public interface Serializer {

    /**
     * 序列化 object 序列化byte[]
     *
     * @param object
     * @param <T>
     * @return
     */
    <T> byte[] serialize(T object);

    /**
     * 将byte[]反序列化class
     *
     * @param clazz
     * @param bytes
     * @param <T>
     * @return
     */
    <T> T deSerialize(Class<T> clazz, byte[] bytes);

    enum Algorithm implements Serializer {
        Java {
            @Override
            public <T> byte[] serialize(T object) {
                try {
                    ByteArrayOutputStream bos = new ByteArrayOutputStream();
                    ObjectOutputStream oos = new ObjectOutputStream(bos);
                    oos.writeObject(object);
                    return bos.toByteArray();
                } catch (IOException e) {
                    throw new RuntimeException("序列化失败", e);
                }
            }

            @Override
            public <T> T deSerialize(Class<T> clazz, byte[] bytes) {
                try {
                    ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(bytes));
                    T message = (T) ois.readObject();
                    return message;
                } catch (IOException | ClassNotFoundException e) {
                    throw new RuntimeException("反序列化失败", e);
                }

            }
        }, Gson {
            @Override
            public <T> byte[] serialize(T object) {
                Gson gson = new GsonBuilder().registerTypeAdapter(Class.class, new ClassCodec()).create();
                String s = gson.toJson(object);
                return s.getBytes(StandardCharsets.UTF_8);
            }

            @Override
            public <T> T deSerialize(Class<T> clazz, byte[] bytes) {
                Gson gson = new GsonBuilder().registerTypeAdapter(Class.class, new ClassCodec()).create();
                String s = new String(bytes, StandardCharsets.UTF_8);
                return gson.fromJson(s, clazz);
            }
        }
    }

    //内部类,处理Gson序列化和反序列化 Class类型出错的问题
    static class ClassCodec implements JsonSerializer<Class<?>>, JsonDeserializer<Class<?>> {

        @Override
        public JsonElement serialize(Class<?> src, Type type, JsonSerializationContext jsonSerializationContext) {
            //将class name序列化成Json
            return new JsonPrimitive(src.getName());
        }

        @Override
        public Class<?> deserialize(JsonElement jsonElement, Type type, JsonDeserializationContext jsonDeserializationContext) throws JsonParseException {

            //将JSON反序列化成class
            String str = jsonElement.getAsString();
            try {
                return Class.forName(str);
            } catch (ClassNotFoundException e) {
                //这个方法需要一个JsonParseException异常,因此我们catch住异常时,将异常进行包装,然后返回throw
                throw new JsonParseException(e);
            }
        }
    }
}
